package dada

import (
	"context"
)

// OrderService 订单服务
type OrderService service

// Product 商品信息
type Product struct {
	SKUName      string  `json:"sku_name"`       // 商品名称，限制长度128
	SrcProductNo string  `json:"src_product_no"` // 商品编码，限制长度64
	Count        float64 `json:"count"`          // 商品数量，精确到小数点后两位
	Unit         string  `json:"unit,omitempty"` // 商品单位，默认：件
}

// AddOrderRequest 新增订单请求
type AddOrderRequest struct {
	ShopNo          string  `json:"shop_no"`                  // 门店编号，门店创建后可在门店列表和单页查看
	OriginID        string  `json:"origin_id"`                // 第三方订单ID
	CityCode        string  `json:"city_code"`                // 订单所在城市的code
	CargoPrice      float64 `json:"cargo_price"`              // 订单金额
	IsPrepay        int     `json:"is_prepay"`                // 是否需要垫付 1:是 0:否 (垫付订单金额，非运费)
	ReceiverName    string  `json:"receiver_name"`            // 收货人姓名
	ReceiverAddress string  `json:"receiver_address"`         // 收货人地址
	ReceiverLat     float64 `json:"receiver_lat"`             // 收货人地址纬度（高德坐标系，若是其他地图经纬度需要转化成高德地图经纬度）
	ReceiverLng     float64 `json:"receiver_lng"`             // 收货人地址经度（高德坐标系，若是其他地图经纬度需要转化成高德地图经纬度)
	Callback        string  `json:"callback"`                 // 回调URL
	ReceiverPhone   string  `json:"receiver_phone,omitempty"` // 收货人手机号（手机号和座机号必填一项）
	ReceiverTel     string  `json:"receiver_tel,omitempty"`   // 收货人座机号（手机号和座机号必填一项）
	Tips            float64 `json:"tips,omitempty"`           // 小费（单位：元，精确小数点后一位）
	Info            string  `json:"info,omitempty"`           // 订单备注
	// 食品小吃-1,饮料-2,鲜花-3,文印票务-8,便利店-9,水果生鲜-13,
	// 同城电商-19,医药-20,蛋糕-21,酒品-24,小商品市场-25,服装-26,
	// 汽修零配-27,数码-28,小龙虾-29,火锅-51,其他-5
	CargoType    int     `json:"cargo_type,omitempty"`    // 订单商品类型
	CargoWeight  float64 `json:"cargo_weight,omitempty"`  // 订单重量（单位：Kg）
	CargoNum     int     `json:"cargo_num,omitempty"`     // 订单商品数量
	InvoiceTitle string  `json:"invoice_title,omitempty"` // 发票抬头
	OriginMark   string  `json:"origin_mark,omitempty"`   // 订单来源标示（只支持字母，最大长度为10
	// 订单来源编号，最大长度为30，该字段可以显示在骑士APP订单详情页面，示例：
	// origin_mark_no:"#京东到家#1"
	// 达达骑士APP看到的是: #京东到家#1
	OriginMarkNo string `json:"origin_mark_no,omitempty"`
	// 是否使用保价费（0：不使用保价，1：使用保价； 同时，请确保填写了订单金额（cargo_price））
	// 商品保价费(当商品出现损坏，可获取一定金额的赔付)
	// 保费=配送物品实际价值*费率（5‰），配送物品价值及最高赔付不超过10000元，
	// 最高保费为50元（物品价格最小单位为100元，不足100元部分按100元认定，保价费向上取整数，
	// 如：物品声明价值为201元，保价费为300元*5‰=1.5元，取整数为2元。）
	// 若您选择不保价，若物品出现丢失或损毁，最高可获得平台30元优惠券。 （优惠券直接存入用户账户中）。
	IsUseInsurance     int `json:"is_use_insurance,omitempty"`
	IsFinishCodeNeeded int `json:"is_finish_code_needed,omitempty"` // 收货码（0：不需要；1：需要。收货码的作用是：骑手必须输入收货码才能完成订单妥投）
	// 预约发单时间（预约时间unix时间戳(10位),精确到分;整分钟为间隔，并且需要至少提前5分钟预约，可以支持未来3天内的订单发预约单。）
	DelayPublishTime int `json:"delay_publish_time,omitempty"`
	// 是否选择直拿直送（0：不需要；1：需要。选择直拿直送后，同一时间骑士只能配送此订单至完成，同时，也会相应的增加配送费用）
	IsDirectDelivery int       `json:"is_direct_delivery,omitempty"`
	ProductList      []Product `json:"product_list,omitempty"` // 订单商品明细
	PickUpPos        string    `json:"pick_up_pos,omitempty"`  // 货架信息,该字段可在骑士APP订单备注中展示
}

// AddOrderResponse 新增配送单接口返回
type AddOrderResponse struct {
	Distance     float64 `json:"distance"`      // 配送距离(单位：米)
	Fee          float64 `json:"fee"`           // 实际运费(单位：元)，运费减去优惠券费用
	DeliverFee   float64 `json:"deliverFee"`    // 运费(单位：元)
	CouponFee    float64 `json:"couponFee"`     // 优惠券费用(单位：元)
	Tips         float64 `json:"tips"`          // 小费(单位：元)
	InsuranceFee float64 `json:"insurance_fee"` // 保价费(单位：元)
}

// AddOrder 新增配送单接口
func (s *OrderService) AddOrder(ctx context.Context, sourceID string, body *AddOrderRequest) (*AddOrderResponse, error) {
	endPoint := "api/order/addOrder"
	req, err := s.client.NewRequest(endPoint, sourceID, body)
	if err != nil {
		return nil, err
	}
	resp := new(AddOrderResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, err
}

// ReAddOrderRequest 重新发布订单请求
type ReAddOrderRequest struct {
	ShopNo          string  `json:"shop_no"`                  // 门店编号，门店创建后可在门店列表和单页查看
	OriginID        string  `json:"origin_id"`                // 第三方订单ID
	CityCode        string  `json:"city_code"`                // 订单所在城市的code
	CargoPrice      float64 `json:"cargo_price"`              // 订单金额
	IsPrepay        int     `json:"is_prepay"`                // 是否需要垫付 1:是 0:否 (垫付订单金额，非运费)
	ReceiverName    string  `json:"receiver_name"`            // 收货人姓名
	ReceiverAddress string  `json:"receiver_address"`         // 收货人地址
	ReceiverLat     float64 `json:"receiver_lat"`             // 收货人地址纬度（高德坐标系，若是其他地图经纬度需要转化成高德地图经纬度）
	ReceiverLng     float64 `json:"receiver_lng"`             // 收货人地址经度（高德坐标系，若是其他地图经纬度需要转化成高德地图经纬度)
	Callback        string  `json:"callback"`                 // 回调URL
	ReceiverPhone   string  `json:"receiver_phone,omitempty"` // 收货人手机号（手机号和座机号必填一项）
	ReceiverTel     string  `json:"receiver_tel,omitempty"`   // 收货人座机号（手机号和座机号必填一项）
	Tips            float64 `json:"tips,omitempty"`           // 小费（单位：元，精确小数点后一位）
	Info            string  `json:"info,omitempty"`           // 订单备注
	// 食品小吃-1,饮料-2,鲜花-3,文印票务-8,便利店-9,水果生鲜-13,
	// 同城电商-19,医药-20,蛋糕-21,酒品-24,小商品市场-25,服装-26,
	// 汽修零配-27,数码-28,小龙虾-29,火锅-51,其他-5
	CargoType    int     `json:"cargo_type,omitempty"`    // 订单商品类型
	CargoWeight  float64 `json:"cargo_weight,omitempty"`  // 订单重量（单位：Kg）
	CargoNum     int     `json:"cargo_num,omitempty"`     // 订单商品数量
	InvoiceTitle string  `json:"invoice_title,omitempty"` // 发票抬头
	OriginMark   string  `json:"origin_mark,omitempty"`   // 订单来源标示（只支持字母，最大长度为10
	// 订单来源编号，最大长度为30，该字段可以显示在骑士APP订单详情页面，示例：
	// origin_mark_no:"#京东到家#1"
	// 达达骑士APP看到的是: #京东到家#1
	OriginMarkNo string `json:"origin_mark_no,omitempty"`
	// 是否使用保价费（0：不使用保价，1：使用保价； 同时，请确保填写了订单金额（cargo_price））
	// 商品保价费(当商品出现损坏，可获取一定金额的赔付)
	// 保费=配送物品实际价值*费率（5‰），配送物品价值及最高赔付不超过10000元，
	// 最高保费为50元（物品价格最小单位为100元，不足100元部分按100元认定，保价费向上取整数，
	// 如：物品声明价值为201元，保价费为300元*5‰=1.5元，取整数为2元。）
	// 若您选择不保价，若物品出现丢失或损毁，最高可获得平台30元优惠券。 （优惠券直接存入用户账户中）。
	IsUseInsurance     int `json:"is_use_insurance,omitempty"`
	IsFinishCodeNeeded int `json:"is_finish_code_needed"` // 收货码（0：不需要；1：需要。收货码的作用是：骑手必须输入收货码才能完成订单妥投）
	// 预约发单时间（预约时间unix时间戳(10位),精确到分;整分钟为间隔，并且需要至少提前5分钟预约，可以支持未来3天内的订单发预约单。）
	DelayPublishTime int `json:"delay_publish_time,omitempty"`
	// 是否选择直拿直送（0：不需要；1：需要。选择直拿直送后，同一时间骑士只能配送此订单至完成，同时，也会相应的增加配送费用）
	IsDirectDelivery int       `json:"is_direct_delivery"`
	ProductList      []Product `json:"product_list,omitempty"` // 订单商品明细
	PickUpPos        string    `json:"pick_up_pos,omitempty"`  // 货架信息,该字段可在骑士APP订单备注中展示
}

// ReAddOrderResponse 重新发布订单返回
type ReAddOrderResponse struct {
	Distance     float64 `json:"distance"`      // 配送距离(单位：米)
	Fee          float64 `json:"fee"`           // 实际运费(单位：元)，运费减去优惠券费用
	DeliverFee   float64 `json:"deliverFee"`    // 运费(单位：元)
	CouponFee    float64 `json:"couponFee"`     // 优惠券费用(单位：元)
	Tips         float64 `json:"tips"`          // 小费(单位：元)
	InsuranceFee float64 `json:"insurance_fee"` // 保价费(单位：元)
}

// ReAddOrder 重新发布订单接口
func (s *OrderService) ReAddOrder(ctx context.Context, sourceID string, body *ReAddOrderRequest) (*ReAddOrderResponse, error) {
	endPoint := "api/order/reAddOrder"
	req, err := s.client.NewRequest(endPoint, sourceID, body)
	if err != nil {
		return nil, err
	}
	resp := new(ReAddOrderResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, err
}

// FormalCancelRequest 取消订单请求
type FormalCancelRequest struct {
	OrderID        string `json:"order_id"`                // 第三方订单编号
	CancelReasonID int    `json:"cancel_reason_id"`        // 取消原因ID
	CancelReason   string `json:"cancel_reason,omitempty"` // 取消原因(当取消原因ID为其他时，此字段必填)
}

//取消原因列表
//取消ID	取消原因
//1	没有配送员接单
//2	配送员没来取货
//3	配送员态度太差
//4	顾客取消订单
//5	订单填写错误
//34	配送员让我取消此单
//35	配送员不愿上门取货
//36	我不需要配送了
//37	配送员以各种理由表示无法完成订单
//10000	其他

// FormalCancelResponse 取消订单返回
type FormalCancelResponse struct {
	DeductFee float64 `json:"deduct_fee"` // 扣除的违约金(单位：元)
}

// FormalCancel 取消订单接口
func (s *OrderService) FormalCancel(ctx context.Context, sourceID string, body *FormalCancelRequest) (*FormalCancelResponse, error) {
	endPoint := "api/order/formalCancel"
	req, err := s.client.NewRequest(endPoint, sourceID, body)
	if err != nil {
		return nil, err
	}
	resp := new(FormalCancelResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, err
}

// QueryOrderRequest 订单详情查询请求
type QueryOrderRequest struct {
	OrderID string `json:"order_id"` // 第三方订单编号
}

// QueryOrderResponse 订单详情查询返回
type QueryOrderResponse struct {
	OrderID          string  `json:"orderId"`          // 第三方订单编号
	StatusCode       int     `json:"statusCode"`       // 订单状态(待接单＝1,待取货＝2,配送中＝3,已完成＝4,已取消＝5, 指派单=8,妥投异常之物品返回中=9, 妥投异常之物品返回完成=10, 骑士到店=100,创建达达运单失败=1000 可参考文末的状态说明）
	StatusMsg        string  `json:"statusMsg"`        // 订单状态
	TransporterName  string  `json:"transporterName"`  // 骑手姓名
	TransporterPhone string  `json:"transporterPhone"` // 骑手电话
	TransporterLng   string  `json:"transporterLng"`   // 骑手经度
	TransporterLat   string  `json:"transporterLat"`   // 骑手纬度
	DeliveryFee      float64 `json:"deliveryFee"`      // 配送费,单位为元
	Tips             float64 `json:"tips"`             // 小费,单位为元
	CouponFee        float64 `json:"couponFee"`        // 优惠券费用,单位为元
	InsuranceFee     float64 `json:"insuranceFee"`     // 保价费,单位为元
	ActualFee        float64 `json:"actualFee"`        // 实际支付费用,单位为元
	Distance         float64 `json:"distance"`         // 配送距离,单位为米
	CreateTime       string  `json:"createTime"`       // 发单时间
	AcceptTime       string  `json:"acceptTime"`       // 接单时间,若未接单,则为空
	FetchTime        string  `json:"fetchTime"`        // 取货时间,若未取货,则为空
	FinishTime       string  `json:"finishTime"`       // 送达时间,若未送达,则为空
	CancelTime       string  `json:"cancelTime"`       // 取消时间,若未取消,则为空
	OrderFinishCode  string  `json:"orderFinishCode"`  // 收货码
	DeductFee        float64 `json:"deductFee"`        // 违约金
}

// QueryOrder 订单详情查询  注: 只有当订单被接单后才会有骑手信息，并且在待取货和配送中可以查询骑手实时的坐标信息。
func (s *OrderService) QueryOrder(ctx context.Context, sourceID string, body *QueryOrderRequest) (*QueryOrderResponse, error) {
	endPoint := "api/order/status/query"
	req, err := s.client.NewRequest(endPoint, sourceID, body)
	if err != nil {
		return nil, err
	}
	resp := new(QueryOrderResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, err
}
